package gsw.tool.pluggable.hook.hook;

import android.annotation.SuppressLint;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import gsw.tool.pluggable.hook.handler.BaseHandlerClass;
import gsw.tool.pluggable.hook.handler.HandlerPackageManager;

/**
 * Hook当前ActivityThread的sPackageManager，修改它的getPackageInfo()。
 * 系统调用handleLuachActivity()时，会通过IPackageManage.getPackageInfo()检查Activity的包名。
 * 如果IPackageManage.getPackageInfo()返回的包名为null，则使用activityInfo.applicationInfo.packageName为Activitry的包名；
 * 如果IPackageManage.getPackageInfo()返回的包名不为null，则与activityInfo.applicationInfo.packageName比较，如果不同，就会报错。
 * <p>
 * 现在我们需要设置Activity的包名为插件的包名，就需要拦截IPackageManage.getPackageInfo()，让IPackageManage.getPackageInfo()返回的包名为null。
 * 注意：开启新进程打开插件时，需要对新进程的ActivityThread的mInstrumentation进行Hook。
 */

@SuppressLint("PrivateApi")
public class HookPackageManager extends BaseHookProxy {

    @Override
    protected BaseHandlerClass createHookHandle() {
        return new HandlerPackageManager();
    }

    @Override
    public void onInit(ClassLoader classLoader) {
        try {
            /**
             * 获取系统的ActivityThread对象
             */
            Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
            Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
            currentActivityThreadMethod.setAccessible(true);
            Object currentActivityThread = currentActivityThreadMethod.invoke(null);

            /**
             * 获取ActivityThread的sPackageManager对象
             */
            Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
            sPackageManagerField.setAccessible(true);
            Object sPackageManager = sPackageManagerField.get(currentActivityThread);

            //保存系统对象
            setRealObj(sPackageManager);

            /**
             * 使用代理的IPackageManager对象，替换ActivityThread的sPackageManager对象
             */
            Class<?> iPackageManagerInterface = Class.forName("android.content.pm.IPackageManager");
            Object mPackageManager = Proxy.newProxyInstance(iPackageManagerInterface.getClassLoader()
                    , new Class[]{iPackageManagerInterface}, this);
            sPackageManagerField.set(currentActivityThread, mPackageManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
